package com.a01_2021.thousandstimes.general.service.impl;

import com.a01_2021.thousandstimes.exception.CustomException;
import com.a01_2021.thousandstimes.exception.CustomExceptionType;
import com.a01_2021.thousandstimes.general.entity.SysRole;
import com.a01_2021.thousandstimes.general.entity.SysRoleMenu;
import com.a01_2021.thousandstimes.general.entity.SysUserRole;
import com.a01_2021.thousandstimes.general.mapper.SysRoleMapper;
import com.a01_2021.thousandstimes.general.mapper.SysRoleMenuMapper;
import com.a01_2021.thousandstimes.general.mapper.SysUserRoleMapper;
import com.a01_2021.thousandstimes.general.service.SysMenuService;
import com.a01_2021.thousandstimes.general.service.SysRoleService;
import com.a01_2021.thousandstimes.general.service.SysUserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author FRQ
 * @since 2021-02-22
 */
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {

    @Resource
    SysRoleMapper sysRoleMapper;

    @Resource
    SysUserService sysUserService;

    @Resource
    SysRoleMenuMapper sysRoleMenuMapper;

    @Resource
    SysMenuService sysMenuService;

    @Resource
    SysUserRoleMapper sysUserRoleMapper;

    /**
     * 通过角色名添加角色
     *
     * @param roleName 角色名
     * @return 返还添加角色信息
     * @throws CustomException 当角色名为空或已存在时抛出异常
     */
    @Override
    public SysRole addRole(String roleName, String roleDes) throws CustomException {
        if (StringUtils.isEmpty(roleName)) {
            throw new CustomException(CustomExceptionType.USER_INPUT_ERROR, "角色名不得为空");
        }
        if (this.isRole(roleName)) {
            throw new CustomException(CustomExceptionType.ROLE_HAD_BEEN_SET_ERROR, "角色已存在");
        }
        SysRole sysRole = new SysRole();
        sysRole.setName(roleName);
        if (!StringUtils.isEmpty(roleDes)) {
            sysRole.setDes(roleDes);
        }
        sysRoleMapper.insert(sysRole);
        return sysRole;
    }

    /**
     * 检查传入的角色集是否存在
     *
     * @param roleSet 角色集
     * @return 返还角色集是否存在
     */
    @Override
    public boolean isRole(Set<Long> roleSet) {
        QueryWrapper<SysRole> roleQueryWrapper = new QueryWrapper<>();
        for (Long item : roleSet) {
            roleQueryWrapper.or().eq("id", item);
        }
        int count = sysRoleMapper.selectCount(roleQueryWrapper);
        return count == roleSet.size();
    }

    /**
     * 通过用户id查询具有角色id
     *
     * @param userId 用户id
     * @return List<SysRole> 角色集合
     * @throws CustomException 当用户不存在时抛出该异常
     */
    @Override
    public List<SysRole> getRole(long userId) throws CustomException {
        if (!sysUserService.isUser(userId)) {
            throw new CustomException(CustomExceptionType.USER_NOT_FOUND_ERROR, "用户不存在");
        }
        QueryWrapper<SysUserRole> sysUserRoleQueryWrapper = new QueryWrapper<>();
        sysUserRoleQueryWrapper.eq("user_id", userId);
        List<SysUserRole> sysUserRoleList = sysUserRoleMapper.selectList(sysUserRoleQueryWrapper);
        List<SysRole> sysRoleList = null;
        if (!sysUserRoleList.isEmpty()) {
            QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<>();
            for (SysUserRole item : sysUserRoleList) {
                sysRoleQueryWrapper.or().eq("id", item.getRoleId());
            }
            sysRoleList = sysRoleMapper.selectList(sysRoleQueryWrapper);
        }
        return sysRoleList;
    }

    /**
     * 通过权限id查询角色
     *
     * @param menuId 权限id
     * @return List<SysRole>对应的角色列表
     * @throws CustomException 当权限不存在时抛出该异常
     */
    @Override
    public List<SysRole> getRoleByMenu(long menuId) throws CustomException {
        if (!sysMenuService.isMenu(menuId)) {
            //非有效权限
            throw new CustomException(CustomExceptionType.MENU_NOT_FOUNT_ERROR, "不存在该权限");
        }
        //查询角色-权限表
        QueryWrapper<SysRoleMenu> sysRoleMenuQueryWrapper = new QueryWrapper<>();
        sysRoleMenuQueryWrapper.eq("menu_id", menuId);
        List<SysRoleMenu> sysRoleMenuList = sysRoleMenuMapper.selectList(sysRoleMenuQueryWrapper);
        List<SysRole> sysRoleList = null;//用户列表
        if (!sysRoleMenuList.isEmpty()) {
            //若有对应角色-权限记录存在,查询其对应角色
            QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<>();
            for (SysRoleMenu item : sysRoleMenuList) {
                sysRoleQueryWrapper.or().eq("id", item.getRoleId());
            }
            sysRoleList = sysRoleMapper.selectList(sysRoleQueryWrapper);
        }
        return sysRoleList;
    }

    /**
     * 删除用户权限
     *
     * @param userId 用户id
     */
    @Override
    public void dropByUserId(long userId) {
        QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        sysUserRoleMapper.delete(queryWrapper);
    }

    /**
     * 复制角色（将其权限复制
     *
     * @param roleId   被复制的角色id
     * @param roleName 角色名
     * @param roleDes  角色描述
     * @return Map<String, object> 新角色id，权限id集
     * @throws CustomException 当角色不存在，角色名已存在时抛出该异常
     */
    @Override
    public Map<String, Object> copy(long roleId, String roleName, String roleDes) throws CustomException {
        if (this.notRole(roleId)) {
            throw new CustomException(CustomExceptionType.ROLE_NOT_FOUNT_ERROR, "角色不存在");
        }
        if (this.isRole(roleName)) {
            throw new CustomException(CustomExceptionType.ROLE_HAD_BEEN_SET_ERROR, "角色已存在");
        }
        //添加角色
        SysRole sysRole = new SysRole();
        sysRole.setName(roleName);
        sysRole.setDes(roleDes);
        sysRoleMapper.insert(sysRole);
        //查询被复制角色权限
        QueryWrapper<SysRoleMenu> sysRoleMenuQueryWrapper = new QueryWrapper<>();
        sysRoleMenuQueryWrapper.eq("role_id", roleId);
        List<SysRoleMenu> sysRoleMenuList = sysRoleMenuMapper.selectList(sysRoleMenuQueryWrapper);
        //为新角色添加权限
        for (SysRoleMenu item : sysRoleMenuList) {
            sysRoleMenuMapper.insert(new SysRoleMenu(item.getMenuId(), item.getRoleId()));
        }
        //返还结果
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("roleId", sysRole.getId());
        resultMap.put("menuList", sysRoleMenuList.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toSet()));
        return resultMap;
    }

    /**
     * 通过角色名查询角色是否存在
     *
     * @param roleName 角色名
     * @return 返还是否有对应角色
     */
    @Override
    public boolean isRole(String roleName) {
        QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<>();
        sysRoleQueryWrapper.eq("name", roleName);
        SysRole sysRole = sysRoleMapper.selectOne(sysRoleQueryWrapper);
        return sysRole != null;
    }

    /**
     * 通过角色id查询角色是否不存在
     *
     * @param roleId 角色id
     * @return 返还对应角色是否不存在
     */
    public boolean notRole(long roleId) {
        QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<>();
        sysRoleQueryWrapper.eq("id", roleId);
        Integer count = sysRoleMapper.selectCount(sysRoleQueryWrapper);
        return count != 1;
    }


    /**
     * 通过roleId与menuId集合设置对应角色权限
     *
     * @param roleId     角色id
     * @param setMenuSet menuId集合
     * @return Map<String, Object> 返还roleId，menuId集合
     * @throws CustomException 当角色不存在，权限不存在时抛出
     */
    @Override
    public Map<String, Object> setMenuToRole(long roleId, Set<Long> setMenuSet) throws CustomException {
        if (this.notRole(roleId)) {
            //若设置角色不存在
            throw new CustomException(CustomExceptionType.ROLE_NOT_FOUNT_ERROR, "不存在该角色");
        }
        if (!sysMenuService.isMenu(setMenuSet)) {
            //判断是否均有对应权限存在
            throw new CustomException(CustomExceptionType.ROLE_NOT_FOUNT_ERROR, "不存在对应权限");
        }
        QueryWrapper<SysRoleMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_id", roleId);
        List<SysRoleMenu> oldList = sysRoleMenuMapper.selectList(queryWrapper);//获取现有具有角色表
        Set<Long> oldMenuSet = new HashSet<>();
        for (SysRoleMenu item : oldList) {//将旧权限列表转化为集合
            oldMenuSet.add(item.getMenuId());
        }
        Set<Long> insertSet = new HashSet<>(setMenuSet);//插入menuId
        Set<Long> removeSet = new HashSet<>(oldMenuSet);//删除menuId
        insertSet.removeAll(oldMenuSet);//setMenuSet-oldMenuSet
        removeSet.removeAll(setMenuSet);//oldMenuSet-setMenuSet
        //删除移除权限
        if (!removeSet.isEmpty()) {
            QueryWrapper<SysRoleMenu> queryWrapper1 = new QueryWrapper<>();
            for (long item : removeSet) {
                queryWrapper1.or().eq(true, "menu_id", item);
            }
            sysRoleMenuMapper.delete(queryWrapper1);
        }
        //插入新增权限
        if (!insertSet.isEmpty()) {
            for (Long item : insertSet) {
                sysRoleMenuMapper.insert(new SysRoleMenu(item, roleId));
            }
        }
        List<SysRoleMenu> sysRoleMenus = sysRoleMenuMapper.selectList(queryWrapper);
        Map<String, Object> returnMap = new HashMap<>();
        returnMap.put("roleId", roleId);
        returnMap.put("menuList", sysRoleMenus.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toSet()));
        return returnMap;
    }

    /**
     * 查询全部角色
     *
     * @return 返还全部角色
     */
    public List<SysRole> getAllRole() {
        QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<>();
        return sysRoleMapper.selectList(sysRoleQueryWrapper);
    }

    /**
     * 通过roleId删除角色
     *
     * @param roleId 角色id
     * @throws CustomException 当角色不存在，角色被分配到用户时抛出该异常
     */
    @Override
    public void removeRoleById(long roleId) throws CustomException {
        if (!this.isRoleIdle(roleId)) {
            throw new CustomException(CustomExceptionType.ROLE_IS_NOT_IDLE, "角色未闲置（仍被分配到用户");
        }
        //删除权限连接
        QueryWrapper<SysRoleMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_id", roleId);
        sysRoleMenuMapper.delete(queryWrapper);
        //删除角色
        sysRoleMapper.deleteById(roleId);
    }


    /**
     * 通过roleId检查角色是否未被分配到用户
     *
     * @param roleId 角色id
     * @return 返还Role是否未被分配到用户
     * @throws CustomException 当角色不存在时抛出该异常
     */
    public boolean isRoleIdle(long roleId) throws CustomException {
        if (this.notRole(roleId)) {
            throw new CustomException(CustomExceptionType.ROLE_NOT_FOUNT_ERROR, "找不到该角色");
        }
        QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_id", roleId);
        Integer count = sysUserRoleMapper.selectCount(queryWrapper);
        return count == 0;
    }

    /**
     * 通过roleId强制删除角色
     *
     * @param roleId 角色id
     * @throws CustomException 当角色不存在时抛出该异常
     */
    @Override
    public void forceRemoveRoleById(long roleId) throws CustomException {
        if (this.notRole(roleId)) {
            throw new CustomException(CustomExceptionType.ROLE_NOT_FOUNT_ERROR, "找不到该角色");
        }
        //删除用户-角色连接
        QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_id", roleId);
        sysUserRoleMapper.delete(queryWrapper);
        //删除权限连接
        QueryWrapper<SysRoleMenu> queryWrapper1 = new QueryWrapper<>();
        queryWrapper.eq("role_id", roleId);
        sysRoleMenuMapper.delete(queryWrapper1);
        //删除角色
        sysRoleMapper.deleteById(roleId);
    }
}
